/*jslint sub: true, regexp: true */
/*globals isNaN, parseInt, parseFloat, Options */

/**
 * Общий класс управляемых параметров.
 *
 * @class
 * @name ManageOptions
 * @extends Options
 * @see ManageOptions#registerByCallbacks
 * @see ManageOptions#registerAsBoolean
 * @see ManageOptions#registerAsIdentifier
 * @see ManageOptions#registerAsInteger
 * @see ManageOptions#registerAsString
 * @see ManageOptions#registerByRegExp
 * @see ManageOptions#registerAsListFloats
 * @see ManageOptions#registerAsListIntegers
 * @see ManageOptions#registerAsListStrings
 * @see ManageOptions#registerAsFloat
 * @see ManageOptions#registerAsEnum
 */
var ManageOptions = Options.$extend({

    /**
     * Поля обязательные для использования.
     *
     * @private
     * @field
     * @name ManageOptions#required
     * @see ManageOptions#getRequired
     * @see ManageOptions#addRequired
     * @type {String[]|null}
     */
    required : null,

    /**
     * Обработчики получения параметров запроса.
     *
     * @private
     * @field
     * @name ManageOptions#getters
     * @type {Object}
     */
    getters : null,

    /**
     * Обработчики сохранения параметров запроса.
     *
     * @private
     * @field
     * @name ManageOptions#setters
     * @type {Object}
     */
    setters : null,

    /**
     * Получить поля обязательные для использования.
     *
     * @private
     * @function
     * @name ManageOptions#getRequired
     * @see ManageOptions#required
     * @return {String[]}
     */
    getRequired : function () {
        'use strict';
        if (!this.required) {
            this.required = [];
        }
        return this.required.slice(0);
    },

    /**
     * Добавить список полей обязательных для использования.
     *
     * @private
     * @function
     * @name ManageOptions#addRequired
     * @see ManageOptions#required
     * @param {String|String[]} names Список полей обязательных для использования.
     * @return {void}
     */
    addRequired : function (names) {
        'use strict';
        var self = this;
        if (!this.required) {
            this.required = [];
        }
        if (!(names instanceof Array)) {
            names = String(names || '').
                replace(/^\s+/, '').
                replace(/\s+$/, '').
                split(/\s*,\s*/);
        }
        // Перебираем все названия.
        names.forEach(function (name) {
            name = String(name || '');
            // Проверяем, что название параметра валидно.
            if (!/^[a-z_]\w*$/i.test(String(name || ''))) {
                throw new TypeError('The option name(' + JSON.stringify(name) + ') is not valid.');
            }
            self.required.push(name);
        });
    },

    /**
     * Установить обработчик получения параметра.
     *
     * @private
     * @function
     * @name ManageOptions#setGetter
     * @see ManageOptions#getGetter
     * @param {String} name Название параметра.
     * @param {Function} callback Обработчик получения параметра.
     * @return {void}
     */
    setGetter : function (name, callback) {
        'use strict';
        name = String(name || '');
        // Проверяем, что название параметра валидно.
        if (!/^[a-z_]\w*$/i.test(String(name || ''))) {
            throw new TypeError('The option name(' + JSON.stringify(name) + ') is not valid.');
        }
        // Проверяем, что обработчик задан верно.
        if (typeof callback !== 'function') {
            throw new TypeError('Getter(' + JSON.stringify(name) + ') callback is not function.');
        }
        // Устанавливаем объект обработчиков.
        if (this.getters === null) {
            this.getters = {};
        }
        // Устанавливаем сам обработчик.
        this.getters[name] = callback;
    },

    /**
     * Получить обработчик получения параметров.
     *
     * @private
     * @function
     * @name ManageOptions#getGetter
     * @see ManageOptions#setGetter
     * @param {String} name Название параметра.
     * @return {Function|null}
     */
    getGetter : function (name) {
        'use strict';
        name = String(name || '');
        // Проверяем, что название параметра валидно.
        if (!/^[a-z_]\w*$/i.test(String(name || ''))) {
            throw new TypeError('The option name(' + JSON.stringify(name) + ') is not valid.');
        }
        if (this.getters !== null && typeof this.getters[name] === 'function') {
            return this.getters[name];
        }
        return null;
    },

    /**
     * Установить обработчик задания параметра.
     *
     * @private
     * @function
     * @name ManageOptions#setSetter
     * @see ManageOptions#getSetter
     * @param {String} name Название параметра.
     * @param {Function} callback Обработчик задания параметра.
     * @return {void}
     */
    setSetter : function (name, callback) {
        'use strict';
        name = String(name || '');
        // Проверяем, что название параметра валидно.
        if (!/^[a-z_]\w*$/i.test(String(name || ''))) {
            throw new TypeError('The option name(' + JSON.stringify(name) + ') is not valid.');
        }
        // Проверяем, что обработчик задан верно.
        if (typeof callback !== 'function') {
            throw new TypeError('Setter(' + JSON.stringify(name) + ') callback is not function.');
        }
        // Устанавливаем объект обработчиков.
        if (this.setters === null) {
            this.setters = {};
        }
        // Устанавливаем сам обработчик.
        this.setters[name] = callback;
    },

    /**
     * Получить обработчик задания параметров.
     *
     * @private
     * @function
     * @name ManageOptions#getSetter
     * @see ManageOptions#setSetter
     * @param {String} name Название параметра.
     * @return {Function|null}
     */
    getSetter : function (name) {
        'use strict';
        name = String(name || '');
        // Проверяем, что название параметра валидно.
        if (!/^[a-z_]\w*$/i.test(String(name || ''))) {
            throw new TypeError('The option name(' + JSON.stringify(name) + ') is not valid.');
        }
        if (this.setters !== null && typeof this.setters[name] === 'function') {
            return this.setters[name];
        }
        return null;
    },

    /**
     * Получить параметры в виде простого объекта.
     *
     * @public
     * @function
     * @name ManageOptions#getItems
     * @param {String|String[]} keys Название параметров.
     * @return {Object}
     */
    getItems : function (keys) {
        'use strict';
        var self     = this, // Ссылка на текущий объект.
            names    = [],   // Список ключей конечного объекта.
            results  = {};   // Конечный результат.
        if (['undefined'].indexOf(typeof keys) !== 0) {
            // Преобразуем набор ключей к массиву.
            if (!(keys instanceof Array)) {
                keys = String(keys || '').
                    replace(/^\s+/, '').
                    replace(/\s+$/, '').
                    split(/\s*,\s*/);
            }
            keys.forEach(function (name) {
                // Проверяем, что название параметра валидно.
                if (!/^[a-z_]\w*$/i.test(String(name || ''))) {
                    throw new TypeError('The option name(' + JSON.stringify(name) + ') is not valid.');
                }
                // Добавляем в список ключей.
                if (names.indexOf(name) === -1) {
                    names.push(name);
                }
            });
        } else {
            // Перебираем реально установленные параметры.
            Object.keys(this.$super()).forEach(function (name) {
                // Проверяем, что название параметра валидно.
                if (!/^[a-z_]\w*$/i.test(String(name || ''))) {
                    throw new TypeError('The option name(' + JSON.stringify(name) + ') is not valid.');
                }
                // Добавляем в список ключей.
                if (names.indexOf(name) === -1) {
                    names.push(name);
                }
            });
            // Перебираем все обязательные параметры.
            this.getRequired().forEach(function (name) {
                // Проверяем, что название параметра валидно.
                if (!/^[a-z_]\w*$/i.test(String(name || ''))) {
                    throw new TypeError('The option name(' + JSON.stringify(name) + ') is not valid.');
                }
                // Добавляем в список ключей.
                if (names.indexOf(name) === -1) {
                    names.push(name);
                }
            });
        }
        // Сортируем параметры в алфавитном порядке.
        names.sort(function (a, b) {
            if (a > b) { return 1; }
            if (b > a) { return -1; }
            return 0;
        });
        // Собираем значения в объект.
        names.forEach(function (name) {
            results[name] = self.getItem(name);
        });
        return results;
    },

    /**
     * Установить значение параметра.
     *
     * @public
     * @function
     * @name ManageOptions#setItem
     * @param {String} name Название параметра.
     * @param {String|Number|Boolean} value Значение параметра.
     * @return {void}
     */
    setItem : function (name, value) {
        'use strict';
        var setter = this.getSetter(name);
        if (typeof setter === 'function') {
            // Устанавливаем значение через полученный сеттер.
            this.$super(name, setter.call(this, value, name));
        } else {
            // Устанавливаем значение простым способом.
            this.$super(name, value);
        }
    },

    /**
     * Получить значение параметра.
     *
     * @public
     * @function
     * @name ManageOptions#getItem
     * @param {String} name Название параметра.
     * @param {*} [defaults] Значение по умолчанию, если параметр не был найден.
     * @return {*}
     */
    getItem : function (name, defaults) {
        'use strict';
        var getter = this.getGetter(name);
        if (typeof getter === 'function') {
            // Получаем значение через полученный геттер.
            return getter.call(this, this.$super(name, defaults), name);
        }
        // Получаем значение простым способом.
        return this.$super(name, defaults);
    },

    /**
     * Зарегистрировать параметр через калбеки.
     *
     * @public
     * @function
     * @name ManageOptions#registerByCallback
     * @param {String} name Название параметра.
     * @param {Object} [options] Опции регистрации параметра.
     * @param {Function} [options.getter] Обработчик чтения параметра.
     * @param {Function} [options.setter] Обработчик записи параметра.
     * @return {void}
     */
    registerByCallbacks : function (name, options) {
        'use strict';
        var setter = (options || {})['setter'],
            getter = (options || {})['getter'],
            typeSetter = typeof setter,
            typeGetter = typeof getter;
        // Проверяем, что название параметра валидно.
        name = String(name || '');
        if (!/^[a-z_]\w*$/i.test(String(name || ''))) {
            throw new TypeError('The option name(' + JSON.stringify(name) + ') is not valid.');
        }
        // Обрабатываем обработчик чтения.
        if (typeSetter !== 'function' && typeSetter !== 'undefined') {
            // Показываем ошибку, что калбек задан не верно.
            throw new TypeError('Not valid setter callback.');
        } else if (typeSetter === 'undefined') {
            // Обработчик установки по умолчанию.
            setter = function (value) {
                return value;
            };
        }
        // Обрабатываем обработчик записи.
        if (typeGetter !== 'function' && typeGetter !== 'undefined') {
            // Показываем ошибку, что калбек задан не верно.
            throw new TypeError('Not valid getter callback.');
        } else if (typeGetter === 'undefined') {
            // Обработчик получения по умолчанию.
            getter = function (value) {
                return value;
            };
        }
        // Регистрируем обработчики.
        this.setSetter(name, setter);
        this.setGetter(name, getter);
    },

    /**
     * Зарегистрировать булев параметр.
     *
     * @public
     * @function
     * @name ManageOptions#registerAsBoolean
     * @param {String} name Название параметра.
     * @param {Object} options Параметры регистрации.
     * @param {String} [options.yes='yes'] Значение отвечающее за true.
     * @param {String} [options.no='no'] Значение отвечающее за false.
     * @param {Boolean} [options.required=false] Признак, что параметр обязательный.
     * @param {Boolean} [options.defaults=false] Значение по умолчаю.
     * @return {void}
     */
    registerAsBoolean : function (name, options) {
        'use strict';
        var yes      = String((options || {})['yes'] || '') || 'yes', // Значение отвечающее за true.
            no       = String((options || {})['no']  || '') || 'no',  // Значение отвечающее за false.
            required = !!(options || {})['required'],                 // Признак, что параметр обязательный.
            defaults = !!(options || {})['defaults'];                 // Значение по умолчаю.
        // Если параметр обязательный для использования, то
        // добавляем поле в список обязательных полей.
        if (required === true) {
            this.addRequired(name);
        }
        // Регистрируем булев параметр.
        this.registerByCallbacks(name, {
            'setter' : function (value) {
                var results = false;
                if (typeof value === 'string') {
                    // Вариант, когда значение задано строкой.
                    value   = value.replace(/^\s+/, '').replace(/\s+$/, '').toLowerCase();
                    results = ['true', 'on', 'yes', '1'].indexOf(value) !== -1;
                } else if (typeof value === 'number') {
                    // Вариант, когда значение задано числом.
                    results = !!(value && value > 0);
                } else if (typeof value !== 'boolean') {
                    // Любое другое по типу значение, кроме булевого.
                    results = !!value;
                }
                return results;
            },
            'getter' : function (value) {
                var results   = false,
                    valueType = typeof value;
                if (valueType === 'undefined' && !required) {
                    // Устанавливаем значение по умолчанию.
                    results = defaults;
                } else if (valueType === 'undefined' && required) {
                    // Показываем ошибку, что параметр обязательный.
                    throw new TypeError('Option ' + JSON.stringify(name) + ' required!');
                } else if (typeof value === 'string') {
                    // Вариант, когда значение задано строкой.
                    value   = value.replace(/^\s+/, '').replace(/\s+$/, '').toLowerCase();
                    results = ['true', 'on', 'yes', '1'].indexOf(value) !== -1;
                } else if (typeof value === 'number') {
                    // Вариант, когда значение задано числом.
                    results = !!(value && value > 0);
                } else if (typeof value !== 'boolean') {
                    // Любое другое по типу значение, кроме булевого.
                    results = !!value;
                } else {
                    results = value;
                }
                // Значение параметра строкой.
                return results ? yes : no;
            }
        });
    },

    /**
     * Зарегистрировать строковый параметр.
     *
     * @public
     * @function
     * @name ManageOptions#registerAsString
     * @param {String} name Название параметра.
     * @param {Object} options Параметры регистрации.
     * @param {Boolean} [options.required=false] Признак, что параметр обязательный.
     * @param {Boolean} [options.emptyAllow=false] Признак, что разрешено использовать пустые строки в качестве значения при установке.
     * @param {String} [options.defaults] Значение по умолчанию.
     * @return {void}
     */
    registerAsString : function (name, options) {
        'use strict';
        var required   = !!(options || {})['required'],             // Признак, что параметр обязательный.
            emptyAllow = !!(options || {})['emptyAllow'],           // Признак, что строка может быть пустой.
            defaults   = String((options || {})['defaults'] || ''). // Значение по умолчанию.
                replace(/^\s+/g, '').replace(/\s+$/g, '').replace(/\s+/g, ' ');
        // Проверяем, что название параметра валидно.
        name = String(name || '');
        if (!/^[a-z_]\w*$/i.test(String(name || ''))) {
            throw new TypeError('The option name(' + JSON.stringify(name) + ') is not valid.');
        }
        // Если параметр обязательный для использования, то
        // добавляем поле в список обязательных полей.
        if (required) {
            this.addRequired(name);
        }
        // Устанавливаем строку.
        this.registerByCallbacks(name, {
            'setter' : function (value) {
                // Приводим строку к обезжиренному виду, убираются пробельные
                // символы слева и справа, а также сокращаются пробельные
                // символы внутри.
                value = String(value || '').replace(/^\s+/g, '').
                    replace(/\s+$/g, '').replace(/\s+/g, ' ');
                if (!emptyAllow && !value) {
                    // Если значение пустое, но пустые значения к использованию не разрешены.
                    throw new TypeError('Option ' + JSON.stringify(name) + ' can not be empty.');
                }
                // Строка для хранения.
                return value;
            },
            'getter' : function (value) {
                var valueType = typeof value;
                // Приводим строку к обезжиренному виду, убираются пробельные
                // символы слева и справа, а также сокращаются пробельные
                // символы внутри.
                value = String(value || '').replace(/^\s+/g, '').
                    replace(/\s+$/g, '').replace(/\s+/g, ' ');
                if (valueType === 'undefined' && required) {
                    // Показываем ошибку, что параметр обязательный.
                    throw new TypeError('Option ' + JSON.stringify(name) + ' required!');
                } else if (defaults && !value) {
                    value = defaults;
                }
                return value;
            }
        });
    },

    /**
     * Зарегистрировать идентификатор.
     *
     * @public
     * @function
     * @name ManageOptions#registerAsIdentifier
     * @param {String} name Название параметра.
     * @param {Object} options Параметры регистрации.
     * @param {Boolean} [options.required=false] Признак, что параметр обязательный.
     * @param {Boolean} [options.unsigned=false] Признак, что значение должно быть строго не отрицательным.
     * @param {String} [options.defaults] Значение по умолчанию.
     * @return {void}
     */
    registerAsIdentifier : function (name, options) {
        'use strict';
        var required = !!(options || {})['required'], // Признак, что параметр обязательный.
            unsigned = !!(options || {})['unsigned'], // Признак, что идентификаторы должны быть не отрицательнми.
            defaults = String(parseInt(String((options || {})['defaults'] || '0'), 10) || 0);
        // Проверяем, что название параметра валидно.
        name = String(name || '');
        if (!/^[a-z_]\w*$/i.test(String(name || ''))) {
            throw new TypeError('The option name(' + JSON.stringify(name) + ') is not valid.');
        }
        // Если параметр обязательный для использования, то
        // добавляем поле в список обязательных полей.
        if (required) {
            this.addRequired(name);
        }
        // Регистрируем идентификатор.
        this.registerByCallbacks(name, {
            'setter' : function (value) {
                value = String(value || '');
                if ((unsigned && !/^\s*\d+\s*$/.test(value)) || (!unsigned && !/^\s*\-?\d+\s*$/.test(value))) {
                    // Показываем, ошибку неправильной установки идентификатора.
                    throw new TypeError('Option ' + JSON.stringify(name) + ' is not valid identifier.');
                }
                // Идентификаторы обрабатываем именно как строки
                // из-за того, что они могут быть очень длинные.
                return value.replace(/^\s+/, '').replace(/\s+$/, '');
            },
            'getter' : function (value) {
                var results, valueType = typeof value;
                if (valueType === 'undefined' && !required) {
                    // Устанавливаем значение по умолчанию.
                    results = defaults;
                } else if (valueType === 'undefined' && required) {
                    // Показываем ошибку, что параметр обязательный.
                    throw new TypeError('Option ' + JSON.stringify(name) + ' required!');
                } else if (typeof value === 'string') {
                    if ((unsigned && !/^\s*\d+\s*$/.test(value)) || (!unsigned && !/^\s*\-?\d+\s*$/.test(value))) {
                        // Показываем, ошибку неправильной установки идентификатора.
                        throw new TypeError('Option ' + JSON.stringify(name) + ' is not valid identifier.');
                    }
                    // Вариант, когда значение правильно задано строкой.
                    results = value.replace(/^\s+/, '').replace(/\s+$/, '');
                } else if (typeof value === 'number') {
                    if ((unsigned && !(value >= 0)) || (!unsigned && isNaN(value)) || value !== parseInt(String(value), 10)) {
                        // Показываем, ошибку неправильной установки идентификатора.
                        throw new TypeError('Option ' + JSON.stringify(name) + ' is not valid identifier.');
                    }
                    // Вариант, когда значение задано числом.
                    results = String(parseInt(String(value), 10));
                } else {
                    // Показываем, ошибку неправильной установки идентификатора.
                    throw new TypeError('Option ' + JSON.stringify(name) + ' is not valid identifier.');
                }
                // Значение параметра строкой.
                return results;
            }
        });
    },

    /**
     * Зарегистрировать целочисленный параметр.
     *
     * @public
     * @function
     * @name ManageOptions#registerAsInteger
     * @param {String} name Название параметра.
     * @param {Object} options Параметры регистрации.
     * @param {Boolean} [options.required=false] Признак, что параметр обязательный.
     * @param {Boolean} [options.unsigned=false] Признак, что значение должно быть строго не отрицательным.
     * @param {Number} [options.defaults] Значение по умолчанию, если параметр отсутствует.
     * @return {void}
     */
    registerAsInteger : function (name, options) {
        'use strict';
        var required = !!(options || {})['required'], // Признак, что параметр обязательный.
            unsigned = !!(options || {})['unsigned'], // Признак, что число должно быть не отрицательнм.
            defaults = parseInt(String((options || {})['defaults'] || '0'), 10) || 0;
        // Проверяем, что название параметра валидно.
        name = String(name || '');
        if (!/^[a-z_]\w*$/i.test(String(name || ''))) {
            throw new TypeError('The option name(' + JSON.stringify(name) + ') is not valid.');
        }
        // Если параметр обязательный для использования, то
        // добавляем поле в список обязательных полей.
        if (required) {
            this.addRequired(name);
        }
        // Регистрируем целое число.
        this.registerByCallbacks(name, {
            'setter' : function (value) {
                value = String(Number(String(value || '')));
                if ((unsigned && !/^\s*\d+\s*$/.test(value)) || (!unsigned && !/^\s*\-?\d+\s*$/.test(value))) {
                    // Показываем, ошибку неправильной установки целого числа.
                    throw new TypeError('Option ' + JSON.stringify(name) + ' is not valid integer.');
                }
                // Сохраняем целое число.
                return parseInt(value, 10);
            },
            'getter' : function (value) {
                var results, valueType = typeof value;
                value = String(Number(String(value || '')));
                if (valueType === 'undefined' && !required) {
                    // Устанавливаем значение по умолчанию.
                    results = defaults;
                } else if (valueType === 'undefined' && required) {
                    // Показываем ошибку, что параметр обязательный.
                    throw new TypeError('Option ' + JSON.stringify(name) + ' required!');
                } else if (typeof value === 'string') {
                    if ((unsigned && !/^\s*\d+\s*$/.test(value)) || (!unsigned && !/^\s*\-?\d+\s*$/.test(value))) {
                        // Показываем, ошибку неправильной установки целого числа.
                        throw new TypeError('Option ' + JSON.stringify(name) + ' is not valid integer.');
                    }
                    // Вариант, когда значение правильно задано строкой.
                    results = parseInt(value.replace(/^\s+/, '').replace(/\s+$/, ''), 10);
                } else if (typeof value === 'number') {
                    if ((unsigned && !(value >= 0)) || (!unsigned && isNaN(value)) || value !== parseInt(String(value), 10)) {
                        // Показываем, ошибку неправильной установки целого числа.
                        throw new TypeError('Option ' + JSON.stringify(name) + ' is not valid integer.');
                    }
                    // Вариант, когда значение задано числом.
                    results = value;
                } else {
                    // Показываем, ошибку неправильной установки целого числа.
                    throw new TypeError('Option ' + JSON.stringify(name) + ' is not valid integer.');
                }
                // Значение параметра строкой.
                return String(results);
            }
        });
    },

    /**
     * Зарегистрировать числовой параметр.
     *
     * @public
     * @function
     * @name ManageOptions#registerAsFloat
     * @param {String} name Название параметра.
     * @param {Object} options Параметры регистрации.
     * @param {Boolean} [options.required=false] Признак, что параметр обязательный.
     * @param {Boolean} [options.unsigned=false] Признак, что значение должно быть строго не отрицательным.
     * @param {String} [options.defaults] Значение по умолчанию, если параметр отсутствует.
     * @return {void}
     */
    registerAsFloat : function (name, options) {
        'use strict';
        var required = !!(options || {})['required'],
            unsigned = !!(options || {})['unsigned'],
            defaults = parseFloat(String((options || {})['defaults'] || '0')) || 0;
        // Проверяем, что название параметра валидно.
        name = String(name || '');
        if (!/^[a-z_]\w*$/i.test(String(name || ''))) {
            throw new TypeError('The option name(' + JSON.stringify(name) + ') is not valid.');
        }
        // Если параметр обязательный для использования, то
        // добавляем поле в список обязательных полей.
        if (required) {
            this.addRequired(name);
        }
        // Регистрируем число.
        this.registerByCallbacks(name, {
            'setter' : function (value) {
                value = parseFloat(String(value));
                if (isNaN(value) || (value < 0 && unsigned)) {
                    // Бросаем исключение, если есть попытка установить что-то другое, кроме числа.
                    throw new TypeError('Option ' + JSON.stringify(name) + ' is not valid float.');
                }
                return value;
            },
            'getter' : function (value) {
                var results, valueType = typeof value;
                value = String(Number(String(value || '')));
                if (valueType === 'undefined' && !required) {
                    // Устанавливаем значение по умолчанию.
                    results = defaults;
                } else if (valueType === 'undefined' && required) {
                    // Показываем ошибку, что параметр обязательный.
                    throw new TypeError('Option ' + JSON.stringify(name) + ' required!');
                } else if (typeof value === 'string') {
                    if ((unsigned && !/^\s*\d+(\.\d+)?\s*$/.test(value)) || (!unsigned && !/^\s*\-?\d+(\.\d+)?\s*$/.test(value))) {
                        // Показываем, ошибку неправильной установки числа.
                        throw new TypeError('Option ' + JSON.stringify(name) + ' is not valid float.');
                    }
                    // Вариант, когда значение правильно задано строкой.
                    results = parseFloat(value.replace(/^\s+/, '').replace(/\s+$/, ''));
                } else if (typeof value === 'number') {
                    if ((unsigned && !(value >= 0)) || (!unsigned && isNaN(value))) {
                        // Показываем, ошибку неправильной установки числа.
                        throw new TypeError('Option ' + JSON.stringify(name) + ' is not valid float.');
                    }
                    // Вариант, когда значение задано числом.
                    results = value;
                } else {
                    // Показываем, ошибку неправильной установки целого числа.
                    throw new TypeError('Option ' + JSON.stringify(name) + ' is not valid float.');
                }
                // Значение параметра строкой.
                return String(results);
            }
        });
    },






















    /**
     * Зарегистрировать пречисление.
     *
     * @public
     * @function
     * @name ManageOptions#registerAsEnum
     * @param {String} name Название параметра.
     * @param {Object} options Параметры регистрации.
     * @param {String|String[]} options.list Список значений из которых будет производится выборка и проверка.
     * @param {String} [options.delimiter] Разделитель значений, если список значений задан строкой.
     * @param {Boolean} [options.required=false] Признак, что параметр обязательный.
     * @param {String} [options.defaults] Значение по умолчанию, если параметр отсутствует.
     * @return {void}
     */
    registerAsEnum : function (name, options) {
        'use strict';
        var self      = this,
            required  = !!(options || {})['required'],               // Признак, что поле обязательное.
            delimiter = String((options || {})['delimiter'] || ','), // Разделитель значений.
            list      = (options || {})['list'] || [],               // Список допустимых значений.
            defaults  = (options || {})['defaults'] || [],           // Список значений по умолчанию.
            enumerate = [],
            lower     = [];
        // Если параметр обязательный для использования, то
        // добавляем поле в список обязательных полей.
        if (required) {
            this.addRequired(name);
        }
        // Если список допустимых значений задан не массивом,
        // то всяческим способом пытаемся привести к массиву.
        if (!(list instanceof Array)) {
            list = String(list || '').split(/\s*,\s*/);
        }
        // Проверяем список допустимых значений.
        list.forEach(function (element, index, array) {
            if (typeof element !== 'string') {
                // Показываем ошибку, что в списке допустимы
                // только строки в качестве значений.
                throw new TypeError('The values ​​list must contain only strings.');
            }
            // Обезжириваем каждое значение.
            array[index] = element.replace(/^\s+/, '').
                replace(/\s+$/, '').replace(/\s+/, ' ');
        });
        // Если список значений по умолчанию задан не массивом,
        // то всяческим способом пытаемся привести к массиву.
        if (!(defaults instanceof Array)) {
            defaults = String(defaults || '').split(/\s*,\s*/);
        }
        // Проверяем список значений по умолчанию.
        defaults.forEach(function (element, index, array) {
            if (typeof element !== 'string') {
                // Показываем ошибку, что в списке допустимы только
                // строки для значения по умолчанию.
                throw new TypeError('The defaults ​​list must contain only strings.');
            }
            // Обезжириваем каждое значение.
            element = element.replace(/^\s+/, '').
                replace(/\s+$/, '').replace(/\s+/, ' ');
            // Показываем ошибку, если значения нет в списке допустимых.
            if (list.indexOf(element) === -1) {
                throw new TypeError('Not valid value ' + JSON.stringify(element) + ' in the defaults list.');
            }
            // Сохраняем значение.
            array[index] = element;
        });





        // Приводим для использования список.
        if (typeof list === 'string') {
            list = list.split(delimiter);
        }
        if (!(list instanceof Array)) {
            list = String(list || '').split(',');
        }
        list.forEach(function (value) {
            // Обезжириваем каждое значение списка от пробелов слева и справа,
            // а также от повторяющихся пробелов внутри текста.
            value = removeSpaces(String(value || ''));
            if (value && lower.indexOf(value) === -1) {
                // Добавляем только в том случае, если значения ещё нет, и
                // если переданное значение не пустое.
                lower.push(value.toLowerCase());
                enumerate.push(value);
            }
        });
        if (!enumerate.length) {
            // Бросаем исключение, если список для выбора оказался пустой.
            throw new TypeError('Не верно задан список значений, ожидается не пустое значение.');
        }
        // Устанавливается сеттер на запись значения.
        this.setSetter(name, function (value) {
            // Обезжириваем значение.
            value = removeSpaces(String(value || ''));
            // Проверяем, что значение у нас строго из списка.
            if (lower.indexOf(value.toLowerCase()) === -1) {
                throw new TypeError('Устанавливаемое значение должно быть из списка: ' + enumerate.join(', ') + '!');
            }
            return value;
        });
        // Устанавливается геттер на получение значения.
        this.setGetter(name, function (value) {
            value = String(value || defaults);
            var index = lower.indexOf(value.toLowerCase());
            if (required && !self.hasItem(name)) {
                throw new TypeError('Параметр ' + JSON.stringify(name) + ' обязателен для использования!');
            }
            // Проверяем, что значение у нас строго из списка.
            if (index === -1) {
                throw new TypeError('Устанавливаемое значение должно быть из списка: ' + enumerate.join(', ') + '!');
            }
            // Результат строкой.
            return String(enumerate[index] || '');
        });
    },










    // TODO: остальные методы дописать по мере необходимости !!!

    /**
     * Зарегистрировать с проверкой по регулярному выражению.
     *
     * @public
     * @function
     * @name ManageOptions#registerByRegExp
     * @return {void}
     */
    registerByRegExp : function (name, options) {
        'use strict';
    },

    registerAsListByRegExp : function (name, options) {
        'use strict';
    },

    /**
     * Зарегистрировать список текстовых значений.
     *
     * @public
     * @function
     * @name ManageOptions#registerAsListStrings
     * @return {void}
     */
    registerAsListStrings : function (name, options) {
        'use strict';
    },

    registerAsListIdentifiers : function (name, options) {
        'use strict';
    },

    /**
     * Зарегистрировать список целых значений.
     *
     * @public
     * @function
     * @name ManageOptions#registerAsListIntegers
     * @return {void}
     */
    registerAsListIntegers : function (name, options) {
        'use strict';
        options = extend({}, options);
        var self       = this, // Ссылка на текущий объект.
            unsigned   = !!options['unsigned'],
            required   = !!options['required'],
            emptyAllow = !!options['emptyAllow'];
        // Устанавливается сеттер на запись значения.
        this.setSetter(name, function (value) {
            var result = []; // Массив для сохранения.
            value = removeSpaces(value instanceof Array ? value.join(',') : value || '');
            // Если получилась не пустая строка, то создаём массив из элементов в строке, разделённых запятой, иначе массив пуст.
            value = value.length ? value.split(/\s*,\s*/) : [];
            value.forEach(function (element) {
                element = parseInt(String(element), 10);
                if (isNaN(element)) {
                    // Проверяем, что все элементы списка заданы числом.
                    throw new TypeError('Один из элементов списка параметра ' + JSON.stringify(name) + ' не является числом!');
                }
                if (unsigned && element < 0) {
                    // Проверяем, что все элементы не отрицательные, если есть такое требование.
                    throw new TypeError('Один из элементов списка параметра ' + JSON.stringify(name) + ' является отцательным числом!');
                }
                result.push(element);
            });
            if (emptyAllow && !result.length) {
                // Проверяем, что список не пустой, если есть обязательное требование.
                throw new TypeError('Параметр ' + JSON.stringify(name) + ' должен быть обязательно не пустым списком!');
            }
            return result;
        });
        // Устанавливается геттер на получение значения.
        this.setGetter(name, function (value) {
            if (required && !self.hasItem(name)) {
                throw new TypeError('Параметр ' + JSON.stringify(name) + ' обязателен для использования!');
            }
            // Результат массивом.
            if (typeof value === ' string') {
                if (!value.length) {
                    value = [];
                } else {
                    value = value.split(',');
                }
            }
            if (!(value instanceof Array)) {
                throw new TypeError('Параметр ' + JSON.stringify(name) + ' должен быть обязательно списком!');
            }
            return value;
        });
    },

    /**
     * Зарегистрировать список чисел.
     *
     * @public
     * @function
     * @name ManageOptions#registerAsListFloats
     * @return {void}
     */
    registerAsListFloats : function (name, options) {
        'use strict';
    }

});

